package com.topisv.tms.service.stock.instorage;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.AreaGroup;
import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.EdiGoodsSku;
import com.topisv.tms.entity.SubWarehouseRel;
import com.topisv.tms.entity.User;
import com.topisv.tms.entity.stock.instorage.InstorageBill;
import com.topisv.tms.entity.stock.instorage.InstorageCountTask;
import com.topisv.tms.entity.stock.instorage.InstorageLog;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillItemPre;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillPre;
import com.topisv.tms.entity.stock.instorage.pre.PreInBill;
import com.topisv.tms.entity.stock.oustorage.OutstorageBill;
import com.topisv.tms.entity.task.MdSendOutTask;
import com.topisv.tms.entity.work.ExceptionOrder.ExceptionOrder;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.InStorageBillErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.AreaGroupDao;
import com.topisv.tms.repository.CustomersDao;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.UserDao;
import com.topisv.tms.repository.stock.instorage.InstorageBillDao;
import com.topisv.tms.repository.stock.instorage.InstorageCountTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageLogDao;
import com.topisv.tms.repository.stock.outstorage.OutstorageBillDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillItemPreDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillPreDao;
import com.topisv.tms.repository.task.MdSendOutTaskDao;
import com.topisv.tms.repository.work.ExceptionOrder.ExceptionOrderDao;
import com.topisv.tms.rest.qimen.qmsend.QmRequestSender;
import com.topisv.tms.rest.qimen.qmservice.EntryOrderConfirmService;
import com.topisv.tms.service.account.ShiroDbRealm.ShiroUser;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.utils.WmsContants;
import com.topisv.tms.utils.enums.InstorageStatusEnums;
import com.topisv.tms.utils.enums.MDOrderType;
import com.topisv.tms.utils.enums.PYOrderType;
import com.topisv.tms.utils.enums.StatusEnums;
import com.topisv.tms.utils.enums.TaskStatus;
import com.topisv.tms.utils.rule.TMSTransportRule;

/**
 * 入库单_service
 * 
 * @author ch
 *
 */
@Component
@Transactional(readOnly = true)
public class InstorageBillService extends BaseService {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private InstorageBillDao instorageBillDao;
	@Autowired
	private CustomersDao customersDao;
	@Autowired
	private AreaGroupDao areagroupDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private InstorageCountTaskDao instorageCountTaskDao;
	@Autowired
	private InstorageLogDao logDao;
	@Autowired
	private EdiGoodsSkuDao ediGoodsSkuDao;
	@Autowired
	private OutstorageBillDao outstorageBillDao;
	@Autowired
	private InstorageBillPreDao instorageBillPreDao;
	@Autowired
	private InstorageBillItemPreDao instorageBillItemPreDao;
	@Autowired
	private MdSendOutTaskDao mdSendOutTaskDao;
	@Autowired
	private ExceptionOrderDao exceptionOrderDao;
	@Resource(type = EntryOrderConfirmService.class)
	private QmRequestSender<Map<Object, Object>> entryOrderConfirmService;
	@Autowired
	private JdbcTemplate jdbcTemplate;
	/**
	 * 查找入库单
	 * 
	 * @param customerCode
	 *            商家编码
	 * @param warehouseCode
	 *            仓库编码
	 * @param status
	 *            入库单状态
	 * @param fromDate
	 *            起始时间
	 * @param toDate
	 *            终止时间
	 * @param pageNumber
	 * @param pageSize
	 * @return
	 */
	public Page<InstorageBill> loadBill(String customerCode,
			String warehouseCode, String status, Date fromDate, Date toDate,
			int pageNumber, int pageSize) {
		PageRequest pageRequest = buildPageRequest(pageNumber, pageSize);
		Specification<InstorageBill> spec = this.getWhereClause(customerCode,
				warehouseCode, status, fromDate, toDate);
		Page<InstorageBill> page = this.instorageBillDao.findAll(spec,
				pageRequest);
		return page;
	}

	/**
	 * 封装查询参数
	 * 
	 * @param customerCode
	 *            商家编码
	 * @param warehouseCode
	 *            仓库编码
	 * @param status
	 *            入库单状态
	 * @param fromDate
	 *            起始时间
	 * @param toDate
	 *            终止时间
	 * @return
	 */
	private Specification<InstorageBill> getWhereClause(
			final String customerCode, final String warehouseCode,
			final String status, final Date fromDate, final Date toDate) {
		return new Specification<InstorageBill>() {

			@Override
			public Predicate toPredicate(Root<InstorageBill> r,
					CriteriaQuery<?> q, CriteriaBuilder cb) {

				Predicate pre = cb.conjunction();
				if (fromDate != null) {
					pre.getExpressions().add(
							cb.greaterThan(r.<Date> get("inTime"), fromDate));
				}

				if (toDate != null) {
					pre.getExpressions().add(
							cb.lessThan(r.<Date> get("inTime"), toDate));
				}

				if (StringUtils.isNotBlank(customerCode)) {
					pre.getExpressions().add(
							cb.equal(r.<String> get("customerCode"),
									customerCode));
				}

				if (null != warehouseCode && !"".equals(warehouseCode)) {
					pre.getExpressions().add(
							cb.equal(r.<String> get("inwarehouseCode"),
									warehouseCode));
				}

				if ("1".equals(status)) { // 待点收
					pre.getExpressions().add(
							cb.or(cb.equal(r.<String> get("status"), "1"),
									cb.equal(r.<String> get("status"), "4")));
				} else if ("0".equals(status)) { // 已点收
					pre.getExpressions().add(
							cb.or(cb.equal(r.<String> get("status"), "2"),
									cb.equal(r.<String> get("status"), "3"),
									cb.equal(r.<String> get("status"), "5"),
									cb.equal(r.<String> get("status"), "6")));
				}

				return pre;
			}

		};
	}

	private PageRequest buildPageRequest(int pageNumber, int pagzSize) {
		Sort sort = new Sort(Direction.DESC, "id");
		return new PageRequest(pageNumber - 1, pagzSize, sort);
	}

	/**
	 * 保存入库单
	 * 
	 * @param bill
	 */
	@Transactional(readOnly = false)
	public void saveBill(InstorageBill bill) {
		this.instorageBillDao.save(bill);
	}

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void createNewBill(InstorageBill bill) throws Exception {
		try {

			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject()
					.getPrincipal();
			Date now = new Date();

			// 保存入库单
			this.saveBill(bill);

			// 入库日志
			InstorageLog log = new InstorageLog();
			log.setBillCode(bill.getBillCode());
			log.setWorkerUuid(curUser.jobuuid);
			log.setInfo(curUser.realname + "登记采购入库单.");
			log.setWorkTime(now);
			log.setWorkType("sign"); // 操作类型 ( sign.登记入库单 takeCountTask.领取点收任务
										// finishCount.点收完成 taskUpTask.领取上架任务
										// finishUp.上架完成 )
			this.logDao.save(log);

			// 创建点收任务
			InstorageCountTask countTask = new InstorageCountTask();
			countTask.setBillCode(bill.getBillCode());
			countTask.setCreateTime(now);
			countTask.setCustomerCode(bill.getCustomerCode());
			countTask.setStatus("undo");
			countTask
					.setTaskCode(TMSTransportRule.generateInstorageCountCode());
			countTask.setWarehouseCode(bill.getInwarehouseCode());
			countTask.setErrorFlag(bill.getErrorFlag());
			this.instorageCountTaskDao.save(countTask);

		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 查找入库单
	 * 
	 * @param billId
	 *            入库单ID
	 * @return
	 */
	public InstorageBill loadBillById(Long billId) {
		return this.instorageBillDao.findOne(billId);
	}

	/**
	 * 查询入库单
	 * 
	 * @param instorageCode
	 * @return
	 */
	public InstorageBill loadBillByCode(String billCode) {
		InstorageBill inBill = this.instorageBillDao.loadBillByCode(billCode);
		if(null!=inBill){
			this.setDetail(inBill);
		}
		return inBill;
	}

	/**
	 * 修改入库单状态
	 * 
	 * @param instorageCode
	 *            入库单号
	 * @param status
	 *            状态 0:待登记 (调拨货品已出库，尚未入库) 1:入库登记 2.:入库点收 3:审核通过 4:审核驳回
	 *            5:完成上架任务分配 6:完成上架任务
	 */
	@Transactional(readOnly = false)
	public void updateStatus(String instorageCode, String status) {
		this.instorageBillDao.updateStatus(instorageCode, status);
	}

	@Transactional(readOnly = false)
	public void updatePrintFlag(String printFlag, String billCode) {
		this.instorageBillDao.updatePrintFlag(printFlag, billCode);
	}

	/**
	 * 入库审核
	 * 
	 * @param billCode
	 *            入库单号
	 * @param auditType
	 *            审核类型 pass:通过 notpass:驳回
	 */
	public void audit(String billCode, String auditType) {
		String status = auditType.equals("pass") ? "3" : "4";
		this.instorageBillDao.updateStatus(billCode, status);
	}

	/**
	 * 分页查询
	 * 
	 * @param param
	 * @return
	 */
	public Page<InstorageBill> loadPageByParam(Map<String, Object> param,
			int pageNumber, int pageSize) {
	    // 根据客户单号查询
	    if(StringUtils.isNotBlank((String) param.get("customerOrderNo"))){
	        List<InstorageBillPre> pres = instorageBillPreDao.findBycustomerOrderNo((String) param.get("customerOrderNo"));
	        StringBuffer nos = new StringBuffer();
	        for (InstorageBillPre instorageBillPre : pres) {
                nos.append(instorageBillPre.getBillCode()+":");
            }
	        
	        //add 增加判断当nos的值不为空时,才进行截取 bug570 by zhangweize
			if (nos.length() > 0) {	
				param.put("customerOrderNo", nos.toString().substring(0, nos.length() - 1));
			}
	    }
	    
		String status = (String) param.get("orderbystatus");
		Sort sort = null;
		if (status.equals("status")) {
			sort = new Sort(Sort.Direction.ASC, "status");
		} else {
			sort = new Sort(Sort.Direction.DESC, "id");
		}
		PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize,
				sort);
		Specification<InstorageBill> spec = this.getWhereClause(param);

		Page<InstorageBill> page = this.instorageBillDao.findAll(spec,
				pageRequest);
		List<InstorageBill> billList = page.getContent();
		for (InstorageBill bill : billList) {
			this.setDetail(bill);
		}
		return page;
	}

	/**
	 * 查找入库单
	 * 
	 * @param param
	 * @return
	 */
	public List<InstorageBill> loadByParam(Map<String, Object> param) {
		Specification<InstorageBill> spec = getWhereClause(param);
		Sort sort = new Sort(Direction.DESC, "id");
		List<InstorageBill> billList = this.instorageBillDao
				.findAll(spec, sort);
		for (InstorageBill bill : billList) {
			this.setDetail(bill);
		}
		return billList;
	}

	/**
	 * 设置入库单详细数据
	 * 
	 * @param instorageBillList
	 */
	private void setDetail(InstorageBill bill) {
		// 商家
		String customerCode = bill.getCustomerCode();
		Customers customer = this.customersDao.findByCustomerCode(customerCode);
		bill.setCustomer(customer);

		// 入库仓库
		String inwarehouseCode = bill.getInwarehouseCode();
		AreaGroup inwarehouse = this.areagroupDao
				.findByGroupCode(inwarehouseCode);
		bill.setInwarehouse(inwarehouse);

		// 出库仓库
		String outwarehouseCode = bill.getOutwarehouseCode();
		AreaGroup outwarehouse = this.areagroupDao
				.findByGroupCode(outwarehouseCode);
		bill.setOutwarehouse(outwarehouse);

		// 创建人
		String createrUuid = bill.getCreaterUuid();
		User creater = this.userDao.findByJobuuid(createrUuid);
		bill.setCreater(creater);

		// 入库预约单ID或美的的返仓入库单
		if (PYOrderType.PRE_ORDER.getType().equals(bill.getBillType())
				|| PYOrderType.RETURN_ORDER.getType()
						.equals(bill.getBillType())) {
			InstorageBillPre preBill = this.instorageBillPreDao
					.findByBillCode(bill.getAboutCode());
			if (preBill != null) {
				preBill.setBillItem(instorageBillItemPreDao.query(preBill
						.getId()));
			}
			bill.setPreBill(preBill);
		}

	}

	/**
	 * 查询条件封装
	 * 
	 * @param param
	 * @return
	 */
	private Specification<InstorageBill> getWhereClause(
			final Map<String, Object> param) {

		return new Specification<InstorageBill>() {

			@Override
			public Predicate toPredicate(Root<InstorageBill> r,
					CriteriaQuery<?> q, CriteriaBuilder cb) {
				Predicate pre = cb.conjunction();
				ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject()
						.getPrincipal();

				try {
				    
				    //根据客户单号查询，直接返回
				    String customerOrderNo = (String) param.get("customerOrderNo");
				    if(StringUtils.isNotBlank(customerOrderNo)){
				        String[] customersSplit = customerOrderNo.split(":");
                        ComparisonPredicate[] customersArray = new ComparisonPredicate[customersSplit.length];
                        int j = 0;
                        for (String _customerOrderNo : customersSplit) {
                            customersArray[j] = (ComparisonPredicate) cb
                                    .equal(r.get("aboutCode"),
                                            _customerOrderNo);
                            j++;
                        }
                        pre.getExpressions().add(cb.or(customersArray));
                        return pre;
				    }

					String customerCode = (String) param.get("customerCode");
					if (StringUtils.isNotBlank(customerCode)) {
						pre.getExpressions().add(
								cb.equal(r.<String> get("customerCode"),
										customerCode));
					} else {
						String customers = curUser.customers;
						if (StringUtils.isNotBlank(customers)) {
							String[] customersSplit = customers.split(":");
							ComparisonPredicate[] customersArray = new ComparisonPredicate[customersSplit.length];
							int j = 0;
							for (String _customers : customersSplit) {
								customersArray[j] = (ComparisonPredicate) cb
										.equal(r.get("customerCode"),
												_customers);
								j++;
							}
							pre.getExpressions().add(cb.or(customersArray));
						}
					}

					String warehouseCode = (String) param.get("warehouseCode");
					if (StringUtils.isNotEmpty(warehouseCode)) {
						pre.getExpressions().add(
								cb.equal(r.<String> get("inwarehouseCode"),
										warehouseCode));
					} else {
						String areagroups = curUser.areagroups;
						if (StringUtils.isNotBlank(areagroups)) {
							String[] areagroupSplit = areagroups.split(":");
							ComparisonPredicate[] areagroupArray = new ComparisonPredicate[areagroupSplit.length];
							int j = 0;
							for (String _areagroup : areagroupSplit) {
								areagroupArray[j] = (ComparisonPredicate) cb
										.equal(r.get("inwarehouseCode"),
												_areagroup);
								j++;
							}
							pre.getExpressions().add(cb.or(areagroupArray));
						}

						
					}
					DateFormat df = new SimpleDateFormat(
							"yyyy-MM-dd hh:mm:ss");
					String fromDateStr = (String) param.get("fromDate");
					if (StringUtils.isNotBlank(fromDateStr)) {
						Date fromDate = df.parse(fromDateStr + " 00:00:00");
						pre.getExpressions().add(
								cb.greaterThan(r.<Date> get("createTime"),
										fromDate));
					}

					String toDateStr = (String) param.get("toDate");
					if (StringUtils.isNotBlank(toDateStr)) {
						Date toDate = df.parse(toDateStr + " 23:59:59");
						pre.getExpressions().add(
								cb.lessThan(r.<Date> get("createTime"),
										toDate));
					}

					String status = (String) param.get("status");
					if (StringUtils.isNotEmpty(status)) {
						pre.getExpressions().add(
								cb.equal(r.get("status"), status));
					}else{
						pre.getExpressions().add(
								cb.notEqual(r.get("status"), "-1"));
					}

					String billCode = (String) param.get("billCode");
					if (StringUtils.isNotEmpty(billCode)) {
						pre.getExpressions().add(
								cb.equal(r.get("billCode"), billCode));
					}
				} catch (Exception e) {
				}

				return pre;
			}
		};
	}

	/**
	 * 删除入库单
	 * 
	 * @param id
	 * @throws Exception
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void deleteBill(Long id) throws Exception {
		try {
			InstorageBill bill = this.instorageBillDao.findOne(id);
			this.instorageBillDao.delete(bill);
			InstorageCountTask countTask = this.instorageCountTaskDao
					.loadByBillCode(bill.getBillCode());
			this.instorageCountTaskDao.delete(countTask);
		} catch (Exception e) {
			throw e;
		}

	}
	
	
	/**
	 * 取消入库单
	 *
	 * @param 
	 * @return 
	 * @throws 
	 * @author yuansheng
	 * @version 1.0.0
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public int cancelBill(Long id) {
	    InstorageBill bill = this.instorageBillDao.findOne(id);
	    // 先对状态进行判断，如果状态正确，取消订单 "0"-"待登记" "1"-"入库登记"
	    if (!"0".equals(bill.getStatus()) && !"1".equals(bill.getStatus())) {
            return 0;
        }
	    
	    // 存在相关单号，表示有预约单,需要同时修改预约单状态
	    /*if (StringUtils.isNotBlank(bill.getAboutCode())) {
	        InstorageBillPre billPre = instorageBillPreDao.findByBillCode(bill.getAboutCode());
	        billPre.setOrderStatus(StatusEnums.PREORDER_STATUS_CANEL.getStatus());
	        instorageBillPreDao.save(billPre);
        }*/
	    
	    // 对入库单的处理
	    bill.setStatus(InstorageStatusEnums.CANCEL.getType());
        instorageBillDao.save(bill);
	    return 1;
	}

	/**
	 * API接口创建入库单
	 * 
	 * @param customerCode
	 *            商家编码
	 * @param warehouseCode
	 *            仓库编码
	 * @param boxNum
	 *            箱子数
	 * @param skuNum
	 *            商品种类（有多少种sku）
	 * @param goodsNum
	 *            商品总数
	 * @param aboutBill
	 *            相关单号：如商家的出库单号
	 * @param remarks
	 *            备注信息
	 * @return
	 * @throws Exception
	 */
	public Map<String, String> createInstorageBill_API(String customerCode,
			String warehouseCode, String boxNumStr, String skuNumStr,
			String goodsNumStr, String aboutCode, String remarks)
			throws Exception {
		try {
			Map<String, String> map = new HashMap<String, String>();
			InstorageBill bill = new InstorageBill();
			Date now = new Date();
			bill.setBillType("4"); // 入库单类型 (1. 采购入库 2.调拨入库 3.取消单入库 4.商家登记)
			bill.setBillCode(TMSTransportRule.generateInStorageBillCode()); // 入库单号(编码规则：'RK'+时间,例如：RK201309091212004
																			// )
			bill.setAboutCode(aboutCode);// 相关单号 （调拨入库->调拨单号）
			bill.setCustomerCode(customerCode);// 商户信息
			bill.setInwarehouseCode(warehouseCode);// 入库仓库信息
			if (StringUtils.isNotBlank(boxNumStr)) { // 箱子数量
				Integer boxNum = Integer.valueOf(boxNumStr);
				bill.setBoxNum(boxNum);
			}
			if (StringUtils.isNotBlank(skuNumStr)) {// SKU数量
				Integer skuNum = Integer.valueOf(skuNumStr);
				bill.setSkuNum(skuNum);
			}
			if (StringUtils.isNotBlank(goodsNumStr)) { // 商品数量
				Integer goodsNum = Integer.valueOf(goodsNumStr);
				bill.setGoodsNum(goodsNum);
			}
			bill.setRemarks(remarks);// 备注
			bill.setCreateTime(new Date());// 入库时间
			bill.setStatus("1");// 入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务
								// 3.点收完成 4.领取上架任务 5.上架完成 ）

			this.instorageBillDao.save(bill);

			// 入库日志
			Customers customer = this.customersDao
					.findByCustomerCode(customerCode);
			InstorageLog log = new InstorageLog();
			log.setBillCode(bill.getBillCode());
			log.setInfo(customer.getCustomerName() + "登记采购入库单.");
			log.setWorkTime(now);
			log.setWorkType("sign"); // 操作类型 ( sign.登记入库单 takeCountTask.领取点收任务
										// finishCount.点收完成 taskUpTask.领取上架任务
										// finishUp.上架完成 )
			this.logDao.save(log);

			// 创建点收任务
			InstorageCountTask countTask = new InstorageCountTask();
			countTask.setBillCode(bill.getBillCode());
			countTask.setCreateTime(now);
			countTask.setCustomerCode(bill.getCustomerCode());
			countTask.setStatus("undo");
			countTask.setErrorFlag(bill.getErrorFlag());
			countTask
					.setTaskCode(TMSTransportRule.generateInstorageCountCode());
			countTask.setWarehouseCode(bill.getInwarehouseCode());
			this.instorageCountTaskDao.save(countTask);

			map.put("msg", "success"); // 创建成功
			map.put("billCode", bill.getBillCode()); // 入库单号

			return map;

		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 
	 * @param customerCode
	 *            商家编码
	 * @param sku
	 *            SKU编码
	 * @param barCode
	 *            规格代码，如果无此代码，可与sku编码相同
	 * @param barName
	 *            规格名称
	 * @param goodsName
	 *            商品名称
	 * @param gW
	 *            毛重
	 * @param nW
	 *            净重
	 * @param length
	 *            长
	 * @param width
	 *            宽
	 * @param height
	 *            高
	 * @param color
	 *            颜色
	 * @param size
	 *            尺寸
	 * @return
	 */
	public String createGoodsInfo_API(String customerCode, String sku,
			String barCode, String barName, String goodsName, String GW,
			String NW, String length, String width, String height,
			String color, String size) {

		EdiGoodsSku goods = new EdiGoodsSku();

		// customerCode不能为空
		if (StringUtils.isBlank(customerCode)) {
			return "null_customerCode";
		}
		goods.setCustomerCode(customerCode);

		// sku不能为空
		if (StringUtils.isBlank(sku)) {
			return "null_sku";
		}
		goods.setSku(sku);

		// barCode不能为空
		if (StringUtils.isBlank(barCode)) {
			return "null_barCode";
		}
		goods.setBar(barCode);

		goods.setDes(barName);
		goods.setSkuName(goodsName);
		goods.setGwt(GW);
		goods.setNwt(NW);
		goods.setLen(length);
		goods.setWid(width);
		goods.setHei(height);
		goods.setCol(color);
		goods.setSiz(size);

		this.ediGoodsSkuDao.save(goods);

		return "success";
	}

	/**
	 * void
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void createInBillAgain(Long billId) {
		InstorageBill instorageBill = instorageBillDao.findOne(billId);
		InstorageBillPre preBill = this.instorageBillPreDao
				.findByBillCode(instorageBill.getAboutCode());
		InstorageBill newBill = new InstorageBill();
		Date now = new Date();
		// 入库单类型 (1.采购入库 2.调拨入库 )
		newBill.setBillType(instorageBill.getBillType());
		// 入库单号
		newBill.setBillCode(TMSTransportRule.generateInStorageBillCode());
		// 商户信息
		newBill.setCustomerCode(instorageBill.getCustomerCode());
		// 入库仓库信息
		newBill.setInwarehouseCode(instorageBill.getInwarehouseCode());
		// 箱子数量
		newBill.setBoxNum(0);
		// SKU数量
		newBill.setSkuNum(0);
		// 商品数量
		newBill.setGoodsNum(0);
		// 备注
		newBill.setRemarks("补货");
		// 创建人
		newBill.setCreaterUuid(getShiroUser() == null ? "SYSTEM"
				: getShiroUser().jobuuid);
		// 入库时间
		newBill.setCreateTime(now);
		// 入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务 3.点收完成 4.领取上架任务 5.上架完成 ）
		newBill.setStatus("0");
		// 是否破损件
		newBill.setErrorFlag(instorageBill.getErrorFlag());
		// 相关单号
		newBill.setAboutCode(preBill.getBillCode());
		//
		newBill.setSyncMdFlag("0");
		newBill.setUpdateFlag("0");
		PreInBill preInBill = new PreInBill();
		// preInBill.setPreBill(preBill);
		preInBill.setInBillCode(newBill.getBillCode());
		preBill.getPreInBills().add(preInBill);
		instorageBillDao.save(newBill);
		instorageBillPreDao.save(preBill);

		instorageBill.setUpdateFlag("1");
		instorageBillDao.save(instorageBill);

		if (WmsContants.CUSTOMER_MID.equals(instorageBill.getCustomerCode())) {
			// 更新处理任务
			MdSendOutTask task = mdSendOutTaskDao.findByCustomerOrderNo(preBill
					.getCustomerOrderNo());
			if (task == null) {
				task = new MdSendOutTask();
				task.setCrTime(now);
				task.setCustomerOrderNo(preBill.getCustomerOrderNo());
				task.setWorkNum(0);
				task.setDoneNum(0);
				task.setDealCount(0);
				String orderType = PYOrderType.PRE_ORDER.getType().equals(
						instorageBill.getBillType()) ? MDOrderType.PURCHASE
						.getType() : PYOrderType.RETURN_ORDER.getType().equals(
						instorageBill.getBillType()) ? MDOrderType.RETURN
						.getType() : "";
				task.setOrderType(orderType);
			}
			task.setDealStatus(TaskStatus.UNHAND.getStatus());
			task.setDealIp(null);
			task.setWorkNum(task.getWorkNum() + 1);
			mdSendOutTaskDao.save(task);
		}

	}

	/**
	 * 确认登记
	 * 
	 * @param billId
	 * @throws Exception
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void confirmIn(Long billId, String selectedWarehouseCode)
			throws Exception {
		try {

			InstorageBill bill = this.instorageBillDao.findOne(billId);
			// 已取消的不能确认
			if (InstorageStatusEnums.CANCEL.getType().equals(bill.getStatus())) {
				throw new PaiUException(ErrorCode.ORDER_CANCELED_ERROR,
						new String[] { bill.getBillCode() });
			}
			if (InstorageStatusEnums.REGIST.getType().equals(bill.getStatus())) {
				throw new PaiUException(InStorageBillErrorCode.CONFIRM_ERROR,
						new String[] { bill.getBillCode() });
			}

			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject()
					.getPrincipal();
			Date now = new Date();

			// 修改入库单状态
			bill.setStatus("1");
			bill.setNewstatus("-1");//@张卫泽改 -1代表不走边收货边上架流程
			// 并且修改新分配的仓库
			if (!StringUtils.isEmpty(selectedWarehouseCode)) {
				bill.setInwarehouseCode(selectedWarehouseCode);
			}
			this.instorageBillDao.save(bill);

			// 修改了新的仓库，修改预约单的仓库
			if (!StringUtils.isEmpty(selectedWarehouseCode)) {
				InstorageBillPre pre = instorageBillPreDao.findByBillCode(bill
						.getAboutCode());
				if (pre != null) {
					pre.setInwarehouseCode(bill.getInwarehouseCode());
					instorageBillPreDao.save(pre);
				}
			}

			// 入库日志
			InstorageLog log = new InstorageLog();
			log.setBillCode(bill.getBillCode());
			log.setWorkerUuid(curUser.jobuuid);
			log.setInfo(curUser.realname + "登记入库单.");
			log.setWorkTime(now);
			log.setWorkType("sign"); // 操作类型 ( sign.登记入库单 takeCountTask.领取点收任务
										// finishCount.点收完成 taskUpTask.领取上架任务
										// finishUp.上架完成 )
			this.logDao.save(log);

			// 创建点收任务
			InstorageCountTask countTask = new InstorageCountTask();
			countTask.setBillCode(bill.getBillCode());
			countTask.setCreateTime(now);
			countTask.setCustomerCode(bill.getCustomerCode());
			countTask.setStatus("undo");
			countTask.setErrorFlag(bill.getErrorFlag());
			countTask
					.setTaskCode(TMSTransportRule.generateInstorageCountCode());
			countTask.setWarehouseCode(bill.getInwarehouseCode());
			this.instorageCountTaskDao.save(countTask);

			// 调拨入库才需要
			if ("allot".equals(bill.getBillType())) {
				// 修改出库单状态为：收货确认
				OutstorageBill outBill = this.outstorageBillDao
						.loadByBillCode(bill.getAboutCode());
				outBill.setStatus("6"); // 状态 （1.创建出库单 2.领取拣货任务 3. 拣货完成 4.领取发货任务
										// 5. 发货完成 6.收货确认 )
				outBill.setAboutCode(bill.getBillCode());
				this.outstorageBillDao.save(outBill);
			}

		} catch (Exception e) {
			throw e;
		}
	}

	@Transactional(readOnly = false)
	public InstorageBillPre addInstorageBillPre(InstorageBillPre pre) {
		return instorageBillPreDao.save(pre);
	}

	public List<SubWarehouseRel> querySubWarehouse(String billId)
			throws Exception {
		List<SubWarehouseRel> subWarehouseList = new ArrayList<SubWarehouseRel>();
		InstorageBill instorageBill = instorageBillDao.findOne(Long
				.valueOf(billId));
		if (instorageBill == null) {
			throw new PaiUException(ErrorCode.DATA_ERROR);
		}
		return subWarehouseList;

	}

	public InstorageBillPre findByBillCode(String billCode) {
		InstorageBillPre billPre = instorageBillPreDao.findByBillCode(billCode);
		return billPre;
	}

	public List<InstorageBillItemPre> findByBillPreId(Long id) {
		List<InstorageBillItemPre> items = instorageBillItemPreDao.query(id);
		return items;
	}

	public List<InstorageBill> findInstorageBill(Map<String, Object> param) {
		Specification<InstorageBill> spec = findWhereClause(param);
		List<InstorageBill> list = instorageBillDao.findAll(spec);
		return list;
	}

	private Specification<InstorageBill> findWhereClause(
			final Map<String, Object> searchParams) {

		return new Specification<InstorageBill>() {

			@Override
			public Predicate toPredicate(Root<InstorageBill> r,
					CriteriaQuery<?> q, CriteriaBuilder cb) {
				Predicate pre = cb.conjunction();

				String customerCode = (String) searchParams.get("customerCode");
				if (StringUtils.isNotBlank(customerCode)) {
					pre.getExpressions()
							.add(cb.equal(r.get("customerCode"),
									customerCode.trim()));
				}

				String warehouseCode = (String) searchParams
						.get("warehouseCode");
				if (StringUtils.isNotBlank(warehouseCode)) {
					pre.getExpressions().add(
							cb.equal(r.get("inwarehouseCode"),
									warehouseCode.trim()));
				}

				String billtype = (String) searchParams.get("billType");
				if (StringUtils.isNotBlank(billtype)) {
					pre.getExpressions().add(
							cb.equal(r.get("billType"), billtype.trim()));
				}

				String aboutCode = (String) searchParams.get("aboutCode");
				if (StringUtils.isNotBlank(aboutCode)) {
					pre.getExpressions().add(
							cb.like(r.<String> get("aboutCode"), "%"
									+ aboutCode + "%"));
				}

				Date fromDate = (Date) searchParams.get("fromDate");
				if (fromDate != null) {
					pre.getExpressions().add(
							cb.greaterThanOrEqualTo(r.<Date> get("createTime"),
									fromDate));
				}

				Date toDate = (Date) searchParams.get("toDate");
				if (toDate != null) {
					pre.getExpressions().add(
							cb.lessThanOrEqualTo(r.<Date> get("createTime"),
									toDate));
				}
				pre.getExpressions().add(cb.notEqual(r.get("status"), 6));
				return pre;
			}
		};
	}

	/**
	 * 重发奇门接口
	 * 
	 * @param billId
	 * @throws Exception
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void repeatSendQM(Long billId) throws Exception {
		try {
			InstorageBill bill = this.instorageBillDao.findOne(billId);
			ExceptionOrder eo = exceptionOrderDao.loadByOrderno(bill
					.getAboutCode());
			if (eo == null && !"allot".equals(bill.getBillType())) {
				// 入库单类型 (customer. 采购入库 allot.调拨入库 returnOrder：退回入库 preOrder:
				// 预约入库)
				logger.info("重发奇门接口：不是取消订单上架 正常发送奇门流水。");
				Map<Object, Object> params = new HashMap<Object, Object>();
				params.put("billType", bill.getBillType());
				params.put("status", bill.getStatus());
				params.put("preCode", bill.getAboutCode());
				logger.info("重发奇门接口参数:params:" + params + ";"
						+ bill.getCustomerCode());
				entryOrderConfirmService.send(params, bill.getCustomerCode());
			} else {
				logger.info("重发奇门接口:取消单上架不发送奇门流水。");
			}
		} catch (Exception e) {
			logger.error("repeatSendQMError entryOrderConfirm : " + e);
		}
	}
	/**
	 * 根据aboutCode查询入库单
	 */
	public InstorageBill findInstorageBillByAboutCode(String  aboutCode) {
		InstorageBill inBill =instorageBillDao.loadBillByAboutCode(aboutCode);
		if(null!=inBill){
			this.setDetail(inBill);
		}
		return inBill;
	}
//	public InstorageBill findInstorageBillByBillCode(String  billCode) {
//		return instorageBillDao.loadBillByCode(billCode);
//	}
	/**
	 * 验收单
	 * @param billCode
	 * @return
	 */
	public List<Map<String,Object>> printTaskPageForYS(String billCode,String billType){
		String sql="";
		if(billType.equals("customer")){
			sql="select a.sku_name as skuName, IFNULL(a.spec,'') as spec, b.warehouse_code as warehouseCode, b.customer_code as customerCode, b.bill_code as billCode, b.sku as skuCode,"
					+ " b.goods_num as goodsNum, b.countNum "
			   + " from edi_goods_sku a, ( "
			   + "select b.bill_code,b.customer_code,b.warehouse_code,b.sku,0 as goods_num,b.num as countNum "
			   + "from instorage_count_task a,instorage_count_item b where a.bill_code=b.bill_code and a.bill_code='"+billCode+"'"
			   + ") b WHERE a.customer_code = b.customer_code AND a.sku_id = b.sku";
		}else{
				sql="select a.sku_name as skuName,IFNULL(a.spec,'') as spec,b.about_code as aboutCode,b.create_time as createTime, "
				 +" b.inwarehouse_code as warehouseCode,b.customer_code as customerCode,b.bill_code as billCode, b.sku_code as skuCode,b.goods_num as goodsNum,b.countNum"
				 +" from edi_goods_sku a ,"
				 + "( "
					 +" select c.*,coalesce(d.countNum,0) as countNum from "
					 +" (select a.about_code,date_format(a.create_time,'%Y-%m-%d %H:%I:%S') as create_time ,a.inwarehouse_code,a.customer_code,a.bill_code,c.sku_code,c.goods_num "
					 +"  from instorage_bill a,instorage_bill_pre b,instorage_bill_item_pre c "
					 +"  where a.about_code=b.bill_code and b.id=c.bill_pre_id and a.bill_code='"+billCode+"' )c "
					 +" LEFT JOIN "
					 +" (select bill_code,customer_code,warehouse_code,sku,num as countNum from instorage_count_item where bill_code='"+billCode+"')d "
					 + "on "
					 + "c.bill_code=d.bill_code and c.customer_code=d.customer_code and c.inwarehouse_code=d.warehouse_code  and c.sku_code=d.sku "
				 + ") b"
			     + " where a.customer_code=b.customer_code and a.sku_id=b.sku_code  ";
		}
		return jdbcTemplate.queryForList(sql);
	}
	/**
	 * 验收单打印次数
	 * @param billCode
	 * @return
	 */
	public int updateInstorageBillPrintYsNum(String billCode){
		String sql="update instorage_bill set print_ysnum=print_ysnum+1 where bill_code='"+billCode+"'";
		return jdbcTemplate.update(sql);
	}
	/**
	 * 上架单
	 * @param billCode
	 * @return
	 */
	public List<Map<String,Object>> printUpTaskPageForUp(String billCode){
		String sql="select a.sku_name as skuName,b.billCode,b.aboutCode,b.customerCode,b.warehouseCode,b.errorFlag,b.sku,b.unUpNum "
				+ "from edi_goods_sku a,"
				+ "( "
				+" select a.billCode,a.aboutCode,a.customerCode,a.warehouseCode,"
				+ "CASE "
				+ "WHEN a.error_flag = 'noterror' THEN '完好' "
				+ "WHEN a.error_flag = 'error' THEN '破损' "
				+ " END AS errorFlag,a.sku,(a.countNum-coalesce(b.upNum,0)) as unUpNum from "
				+" ("
				+ " select a.bill_code as billCode,a.about_code as aboutCode,a.customer_code as customerCode,a.inwarehouse_code as warehouseCode, "
				+"  c.error_flag,c.sku_code as sku,sum(c.num) as countNum "
//				+ " d.num as countNum "
				+ "from instorage_bill a,instorage_up_dispatch_task b,instorage_up_sub_task_item  c"
//				+ ",instorage_count_item d "
				+ " where a.id=b.bill_id and  b.task_code=c.task_code  "
//				+ " and a.bill_code=d.bill_code "
//				+ " and c.error_flag=d.error_flag and c.sku_code=d.sku  "
				+ " and a.bill_code='"+billCode+"'"
				+" group by a.bill_code,a.about_code ,a.customer_code ,a.inwarehouse_code ,c.error_flag,c.sku_code "
				+" ) a LEFT JOIN "
				+" ("
				+ " select a.bill_code as billCode,b.sku_code as sku,b.error_flag,sum(num) as upNum "
				+ "from instorage_up_task a,instorage_up_task_item b "
				+ "where a.task_code=b.up_task_code and a.bill_code='"+billCode+"'   group by a.bill_code,b.sku_code,b.error_flag "
				+ ") "
				+" b on a.billCode=b.billCode and a.sku=b.sku and a.error_flag=b.error_flag "
				+") b where a.customer_code=b.customerCode and a.sku_id=b.sku  ";
		return jdbcTemplate.queryForList(sql);
	}
	/**
	 * 上架打印次数
	 * @param billCode
	 * @return
	 */
	public int updateInstorageBillPrintSjNum(String billCode){
		String sql="update instorage_bill set print_sjnum=print_sjnum+1 where bill_code='"+billCode+"'";
		return jdbcTemplate.update(sql);
	}
	public List<Map<String,Object>>  getCountTaskDateByBillCode(String billCode){
		String sql="select date_format(create_time,'%Y-%m-%d') as createTime from instorage_count_task where bill_code='"+billCode+"' order by create_time desc limit 0,1 ";
		return jdbcTemplate.queryForList(sql);
	} 
	
}
